/**
 * @file apiclient.h
 * @brief API客户端类头文件 - 网络通信的核心组件
 *
 * ApiClient是应用程序与后端API服务器通信的核心组件，提供：
 * - RESTful API调用（GET、POST、PUT、DELETE）
 * - JWT令牌管理和自动刷新
 * - 网络错误处理和自动重试
 * - 请求/响应数据序列化
 * - 异步通信和信号槽机制
 */

#ifndef APICLIENT_H
#define APICLIENT_H

// Qt网络和数据处理组件
#include <QObject>              // Qt对象基类
#include <QNetworkAccessManager> // 网络访问管理器
#include <QNetworkRequest>      // 网络请求
#include <QNetworkReply>        // 网络响应
#include <QJsonObject>          // JSON对象处理
#include <QJsonDocument>        // JSON文档处理
#include <QSettings>            // 设置存储
#include <QTimer>               // 定时器
#include <QUrl>                 // URL处理

/**
 * @class ApiClient
 * @brief API客户端类 - 网络通信的核心组件
 *
 * 提供与后端API服务器通信的完整功能：
 * - 支持RESTful API的所有HTTP方法
 * - 自动处理JWT令牌认证和刷新
 * - 网络错误处理和请求重试机制
 * - 异步请求处理和信号槽通知
 * - 请求超时控制和配置管理
 */
class ApiClient : public QObject
{
    Q_OBJECT  // 启用Qt元对象系统

public:
    /**
     * @struct ApiResponse
     * @brief API响应数据结构
     *
     * 封装API服务器返回的响应数据，提供统一的响应格式：
     * - 成功/失败状态
     * - HTTP状态码
     * - 响应数据（JSON格式）
     * - 错误信息和错误码
     * - 时间戳信息
     */
    struct ApiResponse {
        bool success = false;           ///< 请求是否成功
        int statusCode = 0;             ///< HTTP状态码（200、404、500等）
        QJsonObject data;               ///< 响应数据（JSON对象）
        QString errorMessage;           ///< 错误消息（用户友好的描述）
        QString errorCode;              ///< 错误代码（程序处理用的标识）
        qint64 timestamp = 0;           ///< 响应时间戳
    };

    /**
     * @brief 构造函数
     * @param baseUrl API服务器的基础URL（如：http://localhost:8008）
     * @param parent 父对象指针
     *
     * 初始化API客户端，设置基础URL和网络管理器
     */
    explicit ApiClient(const QString &baseUrl, QObject *parent = nullptr);

    // === HTTP方法 - 异步API调用 ===
    /**
     * @brief 发送GET请求
     * @param endpoint API端点路径（如：/api/v1/users）
     * @param params 查询参数（可选，将转换为URL查询字符串）
     *
     * 发送异步GET请求，结果通过requestFinished信号返回
     * 支持查询参数自动编码和令牌认证
     */
    void get(const QString &endpoint, const QJsonObject &params = QJsonObject{});

    /**
     * @brief 发送POST请求
     * @param endpoint API端点路径
     * @param data 请求体数据（JSON格式）
     *
     * 发送异步POST请求，常用于创建资源或提交表单数据
     */
    void post(const QString &endpoint, const QJsonObject &data);

    /**
     * @brief 发送PUT请求
     * @param endpoint API端点路径
     * @param data 请求体数据（JSON格式）
     *
     * 发送异步PUT请求，常用于更新资源
     */
    void put(const QString &endpoint, const QJsonObject &data);

    /**
     * @brief 发送DELETE请求
     * @param endpoint API端点路径
     *
     * 发送异步DELETE请求，用于删除资源
     */
    void del(const QString &endpoint);

    // === 认证管理 ===
    /**
     * @brief 设置访问令牌
     * @param token JWT访问令牌
     *
     * 设置用于API认证的访问令牌，会自动保存到本地设置
     */
    void setToken(const QString &token);

    /**
     * @brief 获取当前访问令牌
     * @return 当前的JWT访问令牌
     */
    QString getToken() const;

    /**
     * @brief 设置刷新令牌
     * @param refreshToken JWT刷新令牌
     *
     * 设置用于自动刷新访问令牌的刷新令牌
     */
    void setRefreshToken(const QString &refreshToken);

    /**
     * @brief 获取当前刷新令牌
     * @return 当前的JWT刷新令牌
     */
    QString getRefreshToken() const;

    /**
     * @brief 清除所有令牌
     *
     * 清除内存和本地存储中的所有认证令牌
     */
    void clearTokens();

    /**
     * @brief 检查是否已认证
     * @return true表示已有有效的访问令牌，false表示未认证
     */
    bool isAuthenticated() const;

    // === 配置管理 ===
    /**
     * @brief 设置请求超时时间
     * @param milliseconds 超时时间（毫秒）
     *
     * 设置网络请求的超时时间，超时后会自动取消请求
     */
    void setTimeout(int milliseconds);

    /**
     * @brief 设置重试次数
     * @param count 最大重试次数
     *
     * 设置网络请求失败时的最大重试次数
     */
    void setRetryCount(int count);

signals:
    /**
     * @brief 请求完成信号
     * @param endpoint 请求的API端点
     * @param response 服务器响应数据
     *
     * 当API请求完成时发出，无论成功或失败都会发出此信号
     */
    void requestFinished(const QString &endpoint, const ApiResponse &response);

    /**
     * @brief 需要重新认证信号
     *
     * 当访问令牌过期且刷新令牌也无效时发出，
     * 通知应用程序需要用户重新登录
     */
    void authenticationRequired();

    /**
     * @brief 网络错误信号
     * @param error 错误描述信息
     *
     * 当发生网络连接错误时发出
     */
    void networkError(const QString &error);

    /**
     * @brief 令牌刷新成功信号
     * @param newToken 新的访问令牌
     *
     * 当访问令牌自动刷新成功时发出
     */
    void tokenRefreshed(const QString &newToken);

private slots:
    /**
     * @brief 网络请求完成槽
     *
     * 处理网络请求的响应，包括成功响应和错误处理
     */
    void onReplyFinished();

    /**
     * @brief 令牌刷新完成槽
     *
     * 处理令牌刷新请求的响应
     */
    void onRefreshTokenFinished();

private:
    // === 核心组件 ===
    QNetworkAccessManager *m_networkManager;   ///< 网络访问管理器
    QString m_baseUrl;                          ///< API服务器基础URL

    // === 认证信息 ===
    QString m_accessToken;                      ///< JWT访问令牌
    QString m_refreshToken;                     ///< JWT刷新令牌
    QSettings *m_settings;                      ///< 本地设置存储

    // === 配置参数 ===
    int m_timeout;                              ///< 请求超时时间（毫秒）
    int m_retryCount;                           ///< 最大重试次数

    /**
     * @struct PendingRequest
     * @brief 待处理请求结构
     *
     * 用于存储因令牌过期而需要重试的请求信息
     */
    struct PendingRequest {
        QString endpoint;       ///< API端点
        QString method;         ///< HTTP方法
        QJsonObject data;       ///< 请求数据
        int retryCount;         ///< 已重试次数
    };
    QList<PendingRequest> m_pendingRequests;    ///< 待处理请求队列

    // === 私有方法 ===
    /**
     * @brief 创建网络请求对象
     * @param endpoint API端点
     * @return 配置好的网络请求对象
     *
     * 创建包含认证头、内容类型等信息的网络请求
     */
    QNetworkRequest createRequest(const QString &endpoint);

    /**
     * @brief 处理网络响应
     * @param reply 网络响应对象
     * @param endpoint API端点
     *
     * 解析响应数据并发出相应信号
     */
    void handleResponse(QNetworkReply *reply, const QString &endpoint);

    /**
     * @brief 刷新访问令牌
     *
     * 使用刷新令牌向服务器请求新的访问令牌
     */
    void refreshAccessToken();

    /**
     * @brief 解析API响应
     * @param reply 网络响应对象
     * @return 解析后的API响应结构
     *
     * 将网络响应解析为标准的ApiResponse结构
     */
    ApiResponse parseResponse(QNetworkReply *reply);

    /**
     * @brief 重试请求
     * @param request 待重试的请求信息
     *
     * 重新发送因令牌过期而失败的请求
     */
    void retryRequest(const PendingRequest &request);

    /**
     * @brief 保存令牌到本地
     *
     * 将访问令牌和刷新令牌保存到QSettings
     */
    void saveTokens();

    /**
     * @brief 从本地加载令牌
     *
     * 从QSettings加载保存的令牌信息
     */
    void loadTokens();
};

#endif // APICLIENT_H
